﻿using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

namespace RunAs
{
    internal class WindowNativeMethod
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
    int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        public static WindowsIdentity GetWindowIdentityByUserAndPaswd(string username, string password, string domain = "")
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            //This parameter causes LogonUser to create a primary token.
            const int LOGON32_LOGON_INTERACTIVE = 2;

            SafeTokenHandle safeTokenHandle = null;
            try
            {
                bool returnValue = LogonUser(username, domain, password,
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                out safeTokenHandle);
                if (returnValue)
                {
                    return new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
                }else
                {
                    return null;
                }
            } finally
            {
                
                safeTokenHandle?.Dispose();
            }
        }

        // 判断某用户是否拥有某权限
        public static bool UserHasFileSystemRightsForPath(WindowsIdentity identity, string path, FileSystemRights systemRights)
        {
            WindowsPrincipal principal = new WindowsPrincipal(identity);
            FileSecurity fileSecurit = File.GetAccessControl(path);
            foreach (FileSystemAccessRule item in fileSecurit.GetAccessRules(true, true, typeof(NTAccount)))
            {
                if (principal.IsInRole(item.IdentityReference.Value) && (item.FileSystemRights & systemRights) != 0)
                {
                    return true;
                }
            }
            return false;
        }


        public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            private SafeTokenHandle()
                : base(true)
            {
            }

            [DllImport("kernel32.dll")]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            [SuppressUnmanagedCodeSecurity]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool CloseHandle(IntPtr handle);

            protected override bool ReleaseHandle()
            {
                return CloseHandle(handle);
            }
        }
    }
}
